package com.bosch.in.db;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import oracle.jdbc.pool.OracleConnectionCacheImpl;
import oracle.jdbc.pool.OracleConnectionPoolDataSource;

import org.apache.log4j.Logger;

public final class OracleConnectionManager {

	private String database;
	private String dbServer;
	private String dbPort;
	private String dbUrl;
	private String dbUser;
	private String dbPassword;
	private String driverType;
	private int numberOfConnection;
	private List<Connection> connectionList;
	private boolean cachingEnabled;
	private int maxConnections;
	private int maxConsBefore;
//	private int conWaiting;
	private static OracleConnectionManager _this = null;
	private OracleConnectionCacheImpl connectionCache;
	private OracleConnectionPoolDataSource connectionPoolDataSource;
	
	private static final Logger LOGGER = Logger.getLogger(OracleConnectionManager.class);

	private OracleConnectionManager(String url, String userId, String pwd) throws FileNotFoundException {
		dbUrl = url;
		dbUser = userId;
		dbPassword = pwd;
		//initialize the members
		init();
	}
	private OracleConnectionManager() throws FileNotFoundException {
		//super(new File(Messages.getString("logfile")));
		database = Messages.getString("rtp2pool.dbname"); //$NON-NLS-1$
		dbServer = Messages.getString("rtp2pool.dbserver"); //$NON-NLS-1$
		dbPort = Messages.getString("rtp2pool.dbport"); //$NON-NLS-1$
		dbUrl = Messages.getString("rtp2pool.url"); //$NON-NLS-1$
		dbUser = Messages.getString("rtp2pool.user"); //$NON-NLS-1$
		dbPassword = Messages.getString("rtp2pool.password"); //$NON-NLS-1$
		driverType = Messages.getString("rtp2pool.drivertype"); //$NON-NLS-1$
		//initialize the members
		init();
		LOGGER.debug("OracleConnectionManager.OracleConnectionManager()>");
	}
	/**
	 * 
	 * <p>Initialize the members of the class.
	 * 
	 * @author �m�t ��m� [apn1kor] [RBIN/EBS2]
	 * @version 1.0 Jan 9, 2007
	 */
	private void init() {
		numberOfConnection = 0;
		connectionList = null;
		cachingEnabled = false;
		maxConsBefore = 0;
//		conWaiting = 0;
		connectionCache = null;
		connectionPoolDataSource = null;
		maxConnections = Integer.parseInt(Messages.getString("rtp2pool.maxconn")); //$NON-NLS-1$
	}
	
	public static OracleConnectionManager getInstance() {
		if(_this==null){
			try {
				_this = new OracleConnectionManager();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return _this;
	}
	public static OracleConnectionManager getInstance(String url, String userId, String pwd) {
		if(_this==null){
			try {
				_this = new OracleConnectionManager( url, userId, pwd);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return _this;
	}
	public static OracleConnectionManager getInstance(String db) {
		if (db != null) {
			if (_this == null) {
				try {
					_this = new OracleConnectionManager();
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
				_this.setDatabase(db);
			}
			return _this;
		}
		return null;
	}

	public void closeAllConnections() {
		try {
			Connection conn = null;
			if (getNumberOfConnection() > 0 || getConnectionList().size() > 0) {
				for (int i = 0; i < getConnectionList().size(); i++) {
					conn = (Connection) getConnectionList().get(i);
					if (!conn.isClosed()) {
						conn.close();
					}
				}
			}
			getConnectionList().clear();
			setNumberOfConnection(0);
			getConnectionCache().close();
			connectionCache = null;
		} catch (Exception exc) {
			//System.out.print("Inside Closing all connection method" + exc); //$NON-NLS-1$
			LOGGER.error("closeAllConnections: Exception caught while closing connection: " //$NON-NLS-1$
							.concat(String.valueOf(String.valueOf(exc
									.getMessage()))));
			exc.printStackTrace(System.err);
		}
	}

	public synchronized void closeConnection(Connection conn) {
		try {
			if (conn != null) {
				conn.close();
				
				removeConnection(conn);
			}

			LOGGER.debug(this + " " + new java.util.Date() + "-closeConnection: " //$NON-NLS-1$ //$NON-NLS-2$
					+ this.database + ": Connections held: " //$NON-NLS-1$
					+ getConnectionCache().getActiveSize());
		} catch (Exception exc) {
			LOGGER.error("closeConnection: Exception caught while closing the connection"); //$NON-NLS-1$
			LOGGER.error("closeConnection: Exception is " + exc.toString()); //$NON-NLS-1$
			exc.printStackTrace();
		}

	}

	@Override
	protected void finalize() throws Throwable {
		closeAllConnections();
		super.finalize();
	}

	public int getNumberOfConnection() {
		if (isCachingEnabled()) {
			return getConnectionCache().getActiveSize();
		} else {
			return numberOfConnection;
		}
	}

	public synchronized Connection getConnection() {

		Connection conTry = null;
//		int i = 1;
//		if (isCachingEnabled()) //We are not using this feature
//		{
//			while (i < 3) {
//				conTry = getConnectionFromCache();
//				if (conTry == null) {
//					try {
//						Thread.currentThread();
//						Thread.sleep(1000L);
//					} catch (Exception exception) {
//					}
//					i++;
////					System.gc();
//					LOGGER.debug(String.valueOf(String.valueOf((new StringBuffer(
//							String.valueOf(String.valueOf(numberOfConnection)))).append(
//							" Connections belegt, ").append(i).append( //$NON-NLS-1$
//							". Versuch")))); //$NON-NLS-1$
//				} else {
//					i = 4;
//				}
//			}
//		} else {
			conTry = getConnectionFromPool();
//		}
		return conTry;
	}

	public OracleConnectionCacheImpl getConnectionCache() {
		if (connectionCache == null) {
			try {
				connectionCache = new OracleConnectionCacheImpl();
				connectionCache.setMaxLimit(maxConnections);
				connectionCache.setCacheScheme(1);
			} catch (SQLException sqlExc) {
				LOGGER.error("Error creating new oracle.jdbc.pool.OracleConnectionCacheImpl instance"); //$NON-NLS-1$
				LOGGER.error("getConnectionPool: Error creating new oracle.jdbc.pool.OracleConnectionCacheImpl" //$NON-NLS-1$
								+ " instance"); //$NON-NLS-1$
				sqlExc.printStackTrace(System.err);
				OracleConnectionCacheImpl oracleconnectioncacheimpl = null;
				return oracleconnectioncacheimpl;
			}

			connectionCache.setURL(getDbUrl());
			connectionCache.setUser(getDbUser());
			connectionCache.setPassword(getDbPassword());
		}
		return connectionCache;
	}

	public Connection getConnectionFromCache() {
		Connection conn = null;
		try {
			conn = getConnectionCache().getConnection();

			getConnectionList().add(conn);
			if (getConnectionCache().getActiveSize() > maxConnections) {
				if (getConnectionCache().getActiveSize() != maxConsBefore) {
					LOGGER.debug(String.valueOf(String.valueOf((new StringBuffer(
							String.valueOf(String.valueOf(getDatabase()))))
							.append(": Active cons = ").append( //$NON-NLS-1$
									getConnectionCache().getActiveSize())
							.append(" limit = ").append(maxConnections)))); //$NON-NLS-1$
					maxConsBefore = getConnectionCache().getActiveSize();
				}
			} else {
				LOGGER.debug(String.valueOf(String.valueOf((new StringBuffer(
						String.valueOf(String.valueOf(getDatabase())))).append(
						": Cons held: ").append( //$NON-NLS-1$
						getConnectionCache().getActiveSize()))));
			}
		} catch (SQLException sqlExc) {
			LOGGER.error("getConnection: Error retrieving database connection from Oracle Connection Cache"); //$NON-NLS-1$
			LOGGER.error("getConnection: Exception is ".concat(String //$NON-NLS-1$
					.valueOf(String.valueOf(sqlExc.toString()))));
			Connection connection = null;
			return connection;
		}
		return conn;
	}

	public Connection getConnectionFromPool() {
		Connection conn = null;
		try {
			conn = getConnectionPoolDataSource().getConnection();
			setNumberOfConnection(getNumberOfConnection() + 1);
			getConnectionList().add(conn);
			if (getNumberOfConnection() >= maxConnections) {
				LOGGER.debug(String.valueOf(String.valueOf((new StringBuffer(String
						.valueOf(String.valueOf(this)))).append(" ").append( //$NON-NLS-1$
						new Date()).append("-getConnection  : ").append( //$NON-NLS-1$
						getDatabase()).append(": maxConnections reached: ") //$NON-NLS-1$
						.append(getNumberOfConnection()))));
			} else {
				LOGGER.debug(String.valueOf(String.valueOf((new StringBuffer(
						String.valueOf(String.valueOf(this)))).append(" ") //$NON-NLS-1$
						.append(new Date()).append("-getConnection  : ") //$NON-NLS-1$
						.append(getDatabase()).append(": Connections held: ") //$NON-NLS-1$
						.append(getNumberOfConnection()))));
			}
		} catch (Exception exc) {
			LOGGER.error("getConnectionFromPool: Exception caught while getting connection from Oracle Con" //$NON-NLS-1$
							+ "nection Pool: ".concat(String.valueOf(String //$NON-NLS-1$
									.valueOf(exc.getMessage()))));
		}

		return conn;
	}
	private List<Connection> getConnectionList() {
		if (connectionList == null) {
			connectionList = new ArrayList<Connection>();
		}
		return connectionList;
	}

	public OracleConnectionPoolDataSource getConnectionPoolDataSource() {
		if (connectionPoolDataSource == null) {
			try {
				connectionPoolDataSource = new OracleConnectionPoolDataSource();
			} catch (SQLException sqlExc) {
				LOGGER.debug("getConnectionPoolDataSource: Exception caught while getting new DataSource"); //$NON-NLS-1$
				sqlExc.printStackTrace(System.err);
			}
			connectionPoolDataSource.setURL(getDbUrl());
			connectionPoolDataSource.setUser(getDbUser());
			connectionPoolDataSource.setPassword(getDbPassword());
		}
		return connectionPoolDataSource;
	}

	public int getCurrentConnectionCount() {
		return getConnectionCache().getActiveSize();
	}

	public String getDatabase() {
		return database;
	}

	public String getDbPassword() {
		return dbPassword;
	}

	public String getDbPort() {
		return dbPort;
	}

	public String getDbServer() {
		return dbServer;
	}

	public String getDbUrl() {
		return dbUrl;
	}

	public String getDbUser() {
		return dbUser;
	}

	public String getDriverType() {
		return driverType;
	}

	public boolean isCachingEnabled() {
		return cachingEnabled;
	}

	private void removeConnection(Connection conn) {
		int idx = getConnectionList().indexOf(conn);
		if (idx >= 0) {
			getConnectionList().remove(idx);
			if (getNumberOfConnection() > 0)
				setNumberOfConnection(getNumberOfConnection() - 1);
		}
	}

	public void setCachingEnabled(boolean newCachingEnabled) {
		if (cachingEnabled != newCachingEnabled) {
			closeAllConnections();
		}
		cachingEnabled = newCachingEnabled;
	}

	private void setNumberOfConnection(int iNumberOfConnection) {
		numberOfConnection = iNumberOfConnection;
	}

	private void setConnectionCache(OracleConnectionCacheImpl newConnectionCache) {
		connectionCache = newConnectionCache;
	}

	public void setConnectionLimit(int value) {
		maxConnections = value;
		try {
			getConnectionCache().setMaxLimit(value);
		} catch (Exception exc) {
			LOGGER.error("setConnectionLimit: Exception caught while setting the maximum number of concurr" //$NON-NLS-1$
							+ "ent database connection in the Connection Cache."); //$NON-NLS-1$
			LOGGER.error("setConnectionLimit: Exception is ".concat(String //$NON-NLS-1$
					.valueOf(String.valueOf(exc.toString()))));
		}
	}

	public void setConnectionPoolDataSource(
			OracleConnectionPoolDataSource newConnectionPoolDataSource) {
		connectionPoolDataSource = newConnectionPoolDataSource;
	}

	/**
	 * 
	 * 
	 * This method will set the url,driver ,user name and pwd
	 *  
	 */
	public void setDatabase() {
		setDbUrl(DBConfig.getDBUrl());
		setDbUser(DBConfig.getDBUserName());
		setDbPassword(DBConfig.getDBPassword());
	}

	public void setDatabase(String newDatabase) {
		if (!database.equals(newDatabase)) {
			database = newDatabase;

			setDbUrl(DBConfig.getDBUrl());
			setDbUser(DBConfig.getDBUserName());
			setDbPassword(DBConfig.getDBPassword());

			closeAllConnections();
			setConnectionCache(null);
		}
	}

	public void setDbPassword(String newDbPassword) {
		dbPassword = newDbPassword;
	}

	public void setDbPort(String newDbPort) {
		dbPort = newDbPort;
	}

	public void setDbServer(String newDbServer) {
		dbServer = newDbServer;
	}

	public void setDbUrl(String newDbUrl) {
		dbUrl = newDbUrl;
	}

	public void setDbUser(String newDbUser) {
		dbUser = newDbUser;
	}

	public void setDriverType(String newDriverType) {
		driverType = newDriverType;
	}

	public void setCacheScheme(int type) {
		if (type != 1 && type != 3 && type != 2) {
			return;
		}
		try {
			getConnectionCache().setCacheScheme(type);
		} catch (Exception exc) {
			LOGGER.error("setCacheScheme: Exception caught while setting the connection cache scheme: " //$NON-NLS-1$
							.concat(String.valueOf(String.valueOf(exc
									.getMessage()))));
			LOGGER.error("setCacheScheme: Scheme not set. Stack trace is printed in System.err."); //$NON-NLS-1$
			exc.printStackTrace(System.err);
		}
	}

	static Class _mthclass$(String x$0) {
		try {
			return Class.forName(x$0);
		} catch (ClassNotFoundException x$1) {
			throw new NoClassDefFoundError(x$1.getMessage());
		}
	}
}